/**
 * Class: Y
 *
 * Purpose: 
 *
 * Created: Jan 27, 2010 @ 9:40:41 AM
 * @author Ken Scott
 */
package org.openfantasia.ps.modifier.surfaces;

import org.openfantasia.ps.modifier.Surface;
import org.openfantasia.ps.particle.Particle;
import org.openfantasia.ui.PColor;
import org.openfantasia.ui.PFrame;
import org.openfantasia.util.math.DPoint2;
import org.openfantasia.util.math.DPoint3;
import org.openfantasia.util.math.PMath;

public class Plane extends Surface {

	protected boolean[] selector;	// = new boolean[]{x, y, z}


	public Plane() {
	}


	public Plane(boolean[] selector, PColor lineColor, PColor fillColor, double friction, double bounce, DPoint3 position, DPoint2 size) {
		super(lineColor, fillColor, friction, bounce);
		this.selector = selector;
		setPosition(new DPoint3(position));
		DPoint3 sz = null;
		double thickness = 1e-6 * PMath.avg(size.p[0], size.p[1]);
		if (selector[0]) {
			sz = new DPoint3(thickness, size.p[0], size.p[1]);
		}
		else if (selector[1]) {
			sz = new DPoint3(size.p[0], thickness, size.p[1]);
		}
		else if (selector[2]) {
			sz = new DPoint3(size.p[0], size.p[1], thickness);
		}
		setSize(sz);
	}


	public boolean hit(Particle particle) {
		boolean result = false;
		double[] p = particle.getPosition().p;
		double[] locP = getPosition().p;
		double[] sizeP = size.p;
		if (selector[0]) {		// X
			if (((locP[0] >= 0) && (p[0] >= locP[0])) ||
					((locP[0] < 0) && (p[0] <= locP[0]))) {
				double minW = locP[1] - sizeP[1] / 2;
				double maxW = locP[1] + sizeP[1] / 2;
				double minH = locP[2] - sizeP[2] / 2;
				double maxH = locP[2] + sizeP[2] / 2;
				result = (p[1] > minW) && (p[1] <= maxW) && (p[2] > minH) && (p[2] <= maxH);
			}
		}
		else if (selector[1]) {	// Y
			if (((locP[1] >= 0) && (p[1] >= locP[1])) ||
					((locP[1] < 0) && (p[1] <= locP[1]))) {
				double minW = locP[0] - sizeP[0] / 2;
				double maxW = locP[0] + sizeP[0] / 2;
				double minH = locP[2] - sizeP[2] / 2;
				double maxH = locP[2] + sizeP[2] / 2;
				result = (p[0] > minW) && (p[0] <= maxW) && (p[2] > minH) && (p[2] <= maxH);
			}
		}
		else if (selector[2]) {	// Z
			if (((locP[2] >= 0) && (p[2] >= locP[2])) ||
					((locP[2] < 0) && (p[2] <= locP[2]))) {
				double minW = locP[0] - sizeP[0] / 2;
				double maxW = locP[0] + sizeP[0] / 2;
				double minH = locP[1] - sizeP[1] / 2;
				double maxH = locP[1] + sizeP[1] / 2;
				result = (p[0] > minW) && (p[0] <= maxW) && (p[1] > minH) && (p[1] <= maxH);
			}
		}
		return result;
	}


	public void act(Particle particle) {
		if (hit(particle)) {
			double[] p = particle.getPosition().p;
			double[] v = particle.getVelocity().p;
			double[] locP = getPosition().p;
			if (selector[0]) {
				p[0] = locP[0];
				v[0] = -v[0] * particle.getBounce() * this.bounce;
				v[1] = v[1] * friction;
				v[2] = v[2] * friction;
			}
			else if (selector[1]) {
				p[1] = locP[1];
				v[0] = v[0] * friction;
				v[1] = -v[1] * particle.getBounce() * this.bounce;
				v[2] = v[2] * friction;
			}
			else if (selector[2]) {
				p[2] = locP[2];
				v[0] = v[0] * friction;
				v[1] = v[1] * friction;
				v[2] = -v[2] * particle.getBounce() * this.bounce;
			}
		}
	}


	public void draw(PFrame frame) {
		double[] sizeP = size.p;

		frame.pushStyle();
		frame.pushMatrix();

		frame.translate(getPosition().copy().neg());
		frame.rotateX(orientation.getX());
		frame.rotateY(orientation.getY());
		frame.rotateZ(orientation.getZ());

		// Draw solid color
		if (fillColor != null) {
			frame.noStroke();
			frame.fill(fillColor);
			frame.box(size);
		}

		// Draw grid
		if (lineColor != null) {
			double[] locP = getPosition().p;
			double minA, maxA, stepA, minB, maxB, stepB;

			frame.noFill();
			frame.stroke(lineColor);
			frame.strokeWeight(1f);

			if (selector[0]) {
				minA = locP[1] - sizeP[1] / 2;
				maxA = locP[1] + sizeP[1] / 2;
				stepA = (maxA - minA) / 10;
				minB = locP[2] - sizeP[2] / 2;
				maxB = locP[2] + sizeP[2] / 2;
				stepB = (maxB - minB) / 10;
				for (double y = minA; y <= maxA; y += stepA) {
					frame.line(locP[0], y, minB, locP[0], y, maxB);
				}
				for (double z = minB; z <= maxB; z += stepB) {
					frame.line(locP[0], minA, z, locP[0], maxA, z);
				}
			}
			else if (selector[1]) {
				minA = locP[0] - sizeP[0] / 2;
				maxA = locP[0] + sizeP[0] / 2;
				stepA = (maxA - minA) / 10;
				minB = locP[2] - sizeP[2] / 2;
				maxB = locP[2] + sizeP[2] / 2;
				stepB = (maxB - minB) / 10;
				for (double x = minA; x <= maxA; x += stepA) {
					frame.line(x, locP[1], minB, x, locP[1], maxB);
				}
				for (double z = minB; z <= maxB; z += stepB) {
					frame.line(minA, locP[1], z, maxA, locP[1], z);
				}
			}
			else if (selector[2]) {
				minA = locP[0] - sizeP[0] / 2;
				maxA = locP[0] + sizeP[0] / 2;
				stepA = (maxA - minA) / 10;
				minB = locP[1] - sizeP[1] / 2;
				maxB = locP[1] + sizeP[1] / 2;
				stepB = (maxB - minB) / 10;
				for (double x = minA; x <= maxA; x += stepA) {
					frame.line(x, minB, locP[2], x, maxB, locP[2]);
				}
				for (double y = minB; y <= maxB; y += stepB) {
					frame.line(minA, y, locP[2], maxA, y, locP[2]);
				}
			}
		}
		frame.popMatrix();
		frame.popStyle();
	}


	@Override
	public String toString() {
		String axis = "";
		if (selector[0]) {
			axis = "X";
		}
		else if (selector[1]) {
			axis = "Y";
		}
		else if (selector[2]) {
			axis = "Z";
		}

		return this.getClass().getSimpleName() + "{" +
				"axis=" + axis +
				", lineColor=" + lineColor +
				", fillColor=" + fillColor +
				", friction=" + friction +
				", bounce=" + bounce +
				", location=" + getPosition() +
				", size=" + size +
				'}';
	}


	public static class X extends Plane {

		private static final boolean[] PATTERN = {true, false, false};


		public X() {
			selector = PATTERN;
		}


		public X(PColor lineColor, PColor fillColor, double friction, double bounce, DPoint3 position, DPoint2 size) {
			super(PATTERN, lineColor, fillColor, friction, bounce, position, size);
		}

	}

	public static class Y extends Plane {

		private static final boolean[] PATTERN = {false, true, false};


		public Y() {
			selector = PATTERN;
		}


		public Y(PColor lineColor, PColor fillColor, double friction, double bounce, DPoint3 position, DPoint2 size) {
			super(PATTERN, lineColor, fillColor, friction, bounce, position, size);
		}

	}

	public static class Z extends Plane {

		private static final boolean[] PATTERN = {false, false, true};


		public Z() {
			selector = PATTERN;
		}


		public Z(PColor lineColor, PColor fillColor, double friction, double bounce, DPoint3 position, DPoint2 size) {
			super(PATTERN, lineColor, fillColor, friction, bounce, position, size);
		}

	}
}